<?php
namespace WDB\Exception;
use WDB;

/**
 * WDB Framework exceptions
 *
 * @author Richard Ejem <richard(at)ejem.cz>
 * @package WDB
 */

/** generic framework exception */
class WDBException extends \Exception{}

/** a method is not supported by a database driver */
class DriverNotFound extends WDBException{}

/** a method is not supported by a database driver */
class UnsupportedByDriver extends WDBException{}

/** this method has not been implemented yet. */
class Unimplemented extends WDBException{}

/** argument of wrong type or data was passed */
class BadArgument extends WDBException{}

/** a mandatory configuration key in config.php is missing */
class ConfigKeyMissing extends WDBException{}

/** insufficient information was passed to perform attempted action */
class ConfigInsufficient extends WDBException{}

/** insufficient information was passed to perform attempted action */
class LangFileNotFound extends WDBException{}

/** a mandatory configuration key in config.php is missing */
class DuplicateName extends WDBException{}

/** trying to write a read-only wdb magic property */
class PropertyException extends WDBException{
    public function __construct($object,$property,$message)
    {
        parent::__construct("Property $property of class ".get_class($object).' '.$message);
    }
}

/** trying to write a read-only structure property */
class ReadOnlyProperty extends PropertyException{
    public function __construct($object,$property)
    {
        parent::__construct($object,$property,' is read only');
    }
}
/** trying to read a write-only structure property */
class WriteOnlyProperty extends PropertyException{
    public function __construct($object,$property)
    {
        parent::__construct($object,$property,' is write only');
    }
}

/** trying to access property that do not exist in a structure */
class NotExistingProperty extends PropertyException{
    public function __construct($object,$property)
    {
        parent::__construct($object,$property,' does not exist');
    }
}

/** database connection failure */
class ConnectionFailed extends WDBException{}

/** invalid characters in an sql identifier */
class InvalidIdentifier extends WDBException{}

/** requested an element of a collection that is out of its index bounds */
class OutOfBounds extends WDBException{}

class QueryError extends WDBException{
    /**wdb query object.
     * @var \WDB\Query\Query
     */
    protected $query;
    public function getQuery() { return $this->query; }

    /**original database driver message
     * @var string
     */
    protected $databaseMessage;
    public function getDatabaseMessage() { return $this->databaseMessage; }

    /**name of schema in which the error occured
     * @var string
     */
    protected $schema;
    public function getSchema() { return $this->schema; }

    /**name of table in which the error occured
     * @var string
     */
    protected $table;
    public function getTable() { return $this->table; }

    /**name of column in which the error occured
     * @var string
     */
    protected $column;
    public function getColumn() { return $this->table; }

    /**name or number of violated constraint
     * @var string
     */
    protected $constraint;
    public function getConstraint() { return $this->constraint; }

    /**value, expression etc. which caused an error
     * @var string
     */
    protected $value;
    public function getValue() { return $this->value; }

    public function __construct($message, $query)
    {
        $this->query = $query;
        $this->databaseMessage = $message;
        parent::__construct($query."\n\n".$message);
    }

    public function logInfo()
    {
        $classSimpleName = \WDB\Utils\Arrays::last(explode('\\', get_class($this)));
        return array(
            'class'=>$classSimpleName,
            'message'=>$this->databaseMessage,
            'schema'=>$this->schema,
            'table'=>$this->table,
            'column'=>$this->column,
            'constraint'=>$this->constraint,
            'value'=>$this->value,
            );
    }
}

abstract class QueryConstraintError extends QueryError
{
    public function __construct($message, $query, $constraintName)
    {
        parent::__construct($message, $query);
        $this->constraint = $constraintName;
    }
}

abstract class QueryColumnError extends QueryError
{
    public function __construct($message, $query, $columnName)
    {
        parent::__construct($message, $query);
        $this->column = $columnName;
    }
}

abstract class QueryExpressionError extends QueryError
{
    public function __construct($message, $query, $expr)
    {
        parent::__construct($message, $query);
        $this->value = $expr;
    }
}

class QueryDuplicateKeyEntry extends QueryConstraintError
{
    public function __construct($message, $query, $entry, $keyNumber)
    {
        parent::__construct($message, $query, $keyNumber);
        $this->value = $entry;
    }
}

class QueryUniqueViolation extends QueryConstraintError {}
class QueryForeignChildViolation extends QueryConstraintError {}
class QueryForeignParentViolation extends QueryConstraintError {}

class QueryNotNullColumn extends QueryColumnError {}
class QueryDataTooLong extends QueryColumnError {}

class QueryWrongFieldWithGroup extends QueryExpressionError {}
class QueryWrongGroupField extends QueryExpressionError {}

class QuerySyntaxError extends QueryError {}
class QueryDivisionByZero extends QueryError {}



/** thrown when trying to retrieve non-existing data (i.e. information about non-existing table, database etc.) */
class NotFound extends WDBException{}

class ColumnNotFound extends WDBException{}

class UnknownColumnType extends WDBException{}

class InvalidOperation extends WDBException{}

class ValidationFailed extends WDBException
{
    protected $errors;
    public function __construct($errors)
    {
        $this->errors = $errors;
        if (count($this->errors) == 0) $this->message = 'unknown error';
        else
        {
            if (is_array($this->errors[0]))
            {
                $r = $this->errors[0]['message'];
            }
            else
            {
                $r = $this->errors[0];
            }
            if (count($this->errors) > 1)
            {
                $r .= ' '.sprintf(WDB\Lang::s('validator.excmore'), (count($this->errors)-1));
            }
            $this->message = $r;
        }
    }
    public function getAllErrors()
    {
        return $this->errors;
    }
}

class ClassNotFound extends WDBException{}

class ValueFormatException extends WDBException{}

class BadEnumeration extends WDBException {}

class KeyException extends WDBException {}

class SchemaNotFound extends WDBException {}

class TableNotFound extends WDBException {}

class InvalidBrokenUTFSetting extends WDBException {}

class InvalidUTFString extends WDBException {}

class GtoParseError extends WDBException {}

class GtoUnknownToken extends GtoParseError {}

class MalformedSerializedData extends WDBException{}

class ParseError extends WDBException{}

class CompileError extends WDBException{}

class InvalidModel extends WDBException{}